#pragma once

#include "ActivityEdge.h"

#include "Activity.h"
#include "ActivityGroup.h"
#include "ActivityNode.h"
#include "ActivityPartition.h"
#include "InterruptibleActivityRegion.h"
#include "RedefinableElement.h"
#include "StructuredActivityNode.h"
#include "ValueSpecification.h"

namespace uml {

ActivityEdge::ActivityEdge(const QString& umlType)
    : NamedElement(umlType) {}

void ActivityEdge::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    NamedElement::fromJson(json, errorList);
    RedefinableElement::fromJson(json, errorList);
    activity_ = JsonSerializable::create<Activity>(json.value("activity"), errorList);

    guard_ = JsonSerializable::create<ValueSpecification>(json.value("guard"), errorList);

    JsonSerializable::fromJsonArray(inGroups_, "inGroups", json, errorList);
    JsonSerializable::fromJsonArray(inPartitions_, "inPartitions", json, errorList);
    inStructuredNode_ = JsonSerializable::create<StructuredActivityNode>(json.value("inStructuredNode"), errorList);

    interrupts_ = JsonSerializable::create<InterruptibleActivityRegion>(json.value("interrupts"), errorList);

    JsonSerializable::fromJsonArray(redefinedEdges_, "redefinedEdges", json, errorList);
    source_ = JsonSerializable::create<ActivityNode>(json.value("source"), errorList);

    target_ = JsonSerializable::create<ActivityNode>(json.value("target"), errorList);

    weight_ = JsonSerializable::create<ValueSpecification>(json.value("weight"), errorList);

}

void ActivityEdge::toJson(QJsonObject& json) {
    NamedElement::toJson(json);
    RedefinableElement::toJson(json);
    if (activity_) {
        QJsonObject activity_json;
        activity_->toJson(activity_json);
        json.insert("activity", activity_json);
    }
    if (guard_) {
        QJsonObject guard_json;
        guard_->toJson(guard_json);
        json.insert("guard", guard_json);
    }
    JsonSerializable::toJsonArray(inGroups_, "inGroups", json);
    JsonSerializable::toJsonArray(inPartitions_, "inPartitions", json);
    if (inStructuredNode_) {
        QJsonObject inStructuredNode_json;
        inStructuredNode_->toJson(inStructuredNode_json);
        json.insert("inStructuredNode", inStructuredNode_json);
    }
    if (interrupts_) {
        QJsonObject interrupts_json;
        interrupts_->toJson(interrupts_json);
        json.insert("interrupts", interrupts_json);
    }
    JsonSerializable::toJsonArray(redefinedEdges_, "redefinedEdges", json);
    if (source_) {
        QJsonObject source_json;
        source_->toJson(source_json);
        json.insert("source", source_json);
    }
    if (target_) {
        QJsonObject target_json;
        target_->toJson(target_json);
        json.insert("target", target_json);
    }
    if (weight_) {
        QJsonObject weight_json;
        weight_->toJson(weight_json);
        json.insert("weight", weight_json);
    }
}

/// <summary>
/// isConsistentWith
/// </summary>
    /// <code>
    /// result = (redefiningElement.oclIsKindOf(ActivityEdge))
    /// </code>
bool ActivityEdge::isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const
{
    return false;
}

/// <summary>
/// activity getter
/// The Activity containing the ActivityEdge, if it is directly owned by an
/// Activity.
/// </summary>
shared_ptr<Activity> ActivityEdge::activity() const {
    return activity_;
}

/// <summary>
/// activity setter
/// The Activity containing the ActivityEdge, if it is directly owned by an
/// Activity.
/// </summary>
void ActivityEdge::setActivity(shared_ptr<Activity> value) {
    activity_ = value;
}

/// <summary>
/// guard getter
/// A ValueSpecification that is evaluated to determine if a token can traverse the
/// ActivityEdge. If an ActivityEdge has no guard, then there is no restriction on
/// tokens traversing the edge.
/// </summary>
shared_ptr<ValueSpecification> ActivityEdge::guard() const {
    return guard_;
}

/// <summary>
/// guard setter
/// A ValueSpecification that is evaluated to determine if a token can traverse the
/// ActivityEdge. If an ActivityEdge has no guard, then there is no restriction on
/// tokens traversing the edge.
/// </summary>
void ActivityEdge::setGuard(shared_ptr<ValueSpecification> value) {
    guard_ = value;
}

/// <summary>
/// inGroups getter
/// ActivityGroups containing the ActivityEdge.
/// </summary>
vector<shared_ptr<ActivityGroup>>& ActivityEdge::inGroups() {
    return inGroups_;
}

/// <summary>
/// inPartitions getter
/// ActivityPartitions containing the ActivityEdge.
/// </summary>
vector<shared_ptr<ActivityPartition>>& ActivityEdge::inPartitions() {
    return inPartitions_;
}

/// <summary>
/// inStructuredNode getter
/// The StructuredActivityNode containing the ActivityEdge, if it is owned by a
/// StructuredActivityNode.
/// </summary>
shared_ptr<StructuredActivityNode> ActivityEdge::inStructuredNode() const {
    return inStructuredNode_;
}

/// <summary>
/// inStructuredNode setter
/// The StructuredActivityNode containing the ActivityEdge, if it is owned by a
/// StructuredActivityNode.
/// </summary>
void ActivityEdge::setInStructuredNode(shared_ptr<StructuredActivityNode> value) {
    inStructuredNode_ = value;
}

/// <summary>
/// interrupts getter
/// The InterruptibleActivityRegion for which this ActivityEdge is an
/// interruptingEdge.
/// </summary>
shared_ptr<InterruptibleActivityRegion> ActivityEdge::interrupts() const {
    return interrupts_;
}

/// <summary>
/// interrupts setter
/// The InterruptibleActivityRegion for which this ActivityEdge is an
/// interruptingEdge.
/// </summary>
void ActivityEdge::setInterrupts(shared_ptr<InterruptibleActivityRegion> value) {
    interrupts_ = value;
}

/// <summary>
/// redefinedEdges getter
/// ActivityEdges from a generalization of the Activity containing this ActivityEdge
/// that are redefined by this ActivityEdge.
/// </summary>
vector<shared_ptr<ActivityEdge>>& ActivityEdge::redefinedEdges() {
    return redefinedEdges_;
}

/// <summary>
/// source getter
/// The ActivityNode from which tokens are taken when they traverse the
/// ActivityEdge.
/// </summary>
shared_ptr<ActivityNode> ActivityEdge::source() const {
    return source_;
}

/// <summary>
/// source setter
/// The ActivityNode from which tokens are taken when they traverse the
/// ActivityEdge.
/// </summary>
void ActivityEdge::setSource(shared_ptr<ActivityNode> value) {
    source_ = value;
}

/// <summary>
/// target getter
/// The ActivityNode to which tokens are put when they traverse the ActivityEdge.
/// </summary>
shared_ptr<ActivityNode> ActivityEdge::target() const {
    return target_;
}

/// <summary>
/// target setter
/// The ActivityNode to which tokens are put when they traverse the ActivityEdge.
/// </summary>
void ActivityEdge::setTarget(shared_ptr<ActivityNode> value) {
    target_ = value;
}

/// <summary>
/// weight getter
/// The minimum number of tokens that must traverse the ActivityEdge at the same
/// time. If no weight is specified, this is equivalent to specifying a constant
/// value of 1.
/// </summary>
shared_ptr<ValueSpecification> ActivityEdge::weight() const {
    return weight_;
}

/// <summary>
/// weight setter
/// The minimum number of tokens that must traverse the ActivityEdge at the same
/// time. If no weight is specified, this is equivalent to specifying a constant
/// value of 1.
/// </summary>
void ActivityEdge::setWeight(shared_ptr<ValueSpecification> value) {
    weight_ = value;
}

} // namespace uml
